package com.ebt.m.proposal_v2.ui.function;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.ebt.m.data.entity.Customer;
import com.ebt.m.proposal_v2.base.Constant;
import com.ebt.m.proposal_v2.bean.ArgProductOption;
import com.ebt.m.proposal_v2.bean.InsuranceCalculator;
import com.ebt.m.proposal_v2.bean.InsuranceEntity;
import com.ebt.m.proposal_v2.bean.event.ExemptResetEvent;
import com.ebt.m.proposal_v2.exempt_rule.ExemptViewSearcher;
import com.ebt.m.proposal_v2.helper.WebViewCallback;
import com.ebt.m.proposal_v2.ui.ProposalNativeAPI;
import com.ebt.m.proposal_v2.ui.view.InsuranceView;
import com.ebt.m.proposal_v2.utils.DataUtils;
import com.ebt.m.proposal_v2.utils.DateUtils;
import com.ebt.m.proposal_v2.widget.dialog.EBTBottomWebDialog;
import com.ebt.m.proposal_v2.widget.view.InsuranceCellView;
import com.ebt.m.commons.utils.Logger;

import org.greenrobot.eventbus.EventBus;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.UnsupportedEncodingException;
import java.util.List;

/**
 * -> 豁免险攻略
 * <p>
 * 1、附加险分为两类： 普通附加险， 豁免附加险； 判断字段riskType
 * <p>
 * 2、普通附加险变更（添加，删除，修改）时，重置当前已有的所有豁免险的保额与保费
 * <p>
 * 3、豁免险添加时，计算添加豁免险的保额与保费
 * <p>
 * ->豁免险保额与保费攻略
 * <p>
 * 1、重置流程
 * <p>
 * 变更完毕后，即该添加的已经添加到险种列表，该修改的已经修改该完成对应参数，该删除的已经从险种列表删除；
 * 找到所有豁免险，针对每一款豁免险遍历所有产品，重新根据豁免范围计算该豁免险的保额与保费
 * <p>
 * ->指定豁免险A
 * <p>
 * 保额计算公式： A豁免范围内， 已经存在的所有险种的保费之和
 * 保费计算公式： 根据计算得出的保额，通过隐式计算器返回的保费
 * <p>
 * <p>
 * ->WebView管理栈攻略
 * <p>
 * 每一款豁免险绑定一个WebView,附带着Url、WebViewCallback统一由WebViewStack管理
 * 每个WebViewCallback绑定一个唯一的id与不一定唯一的url，唯一性由id确保，最好由id与url组合判定
 * 每一个保费计算完成后，根据WebViewCallback绑定的id与url判断删除对应的WebView,并释放掉占用的资源
 * 最后调用clearAll统一释放所有的资源
 *
 * @author archer.qi
 * Created on 2017/7/13.
 */
public class ExemptDao extends SingleWorkerForExemptRisk implements JsLoadSuccessListener {
    private ExemptViewSearcher mExemptSearcher;

    private Handler mMoveDataHandler;

    private WebViewStack mWebViewStack;
    private ViewStack mViewStack;

    public ExemptDao(Context context, InsuranceView view) {
        this.mContext = context;
        mWebViewStack = new WebViewStack();
        mViewStack = new ViewStack();
        mExemptSearcher = new ExemptViewSearcher(view);
    }

    /**
     * 投保人信息发生变更时调用
     *
     * @param applicant
     * @param insured
     */
    public void updateExemptViewAfterApplicantChanged(Customer applicant, Customer insured) {
        // 查询所有豁免投保人的豁免险
        List<InsuranceCellView> mApplicantExemptionViews = mExemptSearcher.getExemptViewsForApplicant();
        if (mApplicantExemptionViews == null || mApplicantExemptionViews.size() == 0) {
            completeAllTask(false, false);
            return;
        }
        for (InsuranceCellView cellView : mApplicantExemptionViews) {
            createNewTask(applicant, insured, cellView);
        }
    }

    /**
     * 添加、删除、修改普通附加险 / 修改主险后调用
     *
     * @param data      修改的附加险数据，用于查询豁免险
     * @param applicant 投保人
     * @param insured   被保人
     */
    public void updateExemptViewAfterModifyCommon(InsuranceEntity data, Customer applicant, Customer insured) {
        if (data == null) {
            completeAllTask(true, true);
            return;
        }
        // 豁免当前产品的所有豁免险
        List<InsuranceCellView> mExemptCellViews = mExemptSearcher.getExemptViews(data);
        if (mExemptCellViews == null || mExemptCellViews.size() == 0) {
            completeAllTask(true, true);
            return;
        }
        for (InsuranceCellView cellView : mExemptCellViews) {
//            updateExemptionView(cellView, applicant, insured);
            createNewTask(applicant, insured, cellView);
        }
    }

    /**
     * 添加、删除、修改普通附加险 / 修改主险后调用
     *
     * @param data      修改的附加险数据，用于查询豁免险
     * @param applicant 投保人
     * @param insured   被保人
     */
    public void updateExemptViewAfterModifyCommon(List<InsuranceEntity> data, Customer applicant, Customer insured) {
        if (data == null || data.size() == 0) {
            completeAllTask(true, true);
            return;
        }
        //所有豁免险
        List<InsuranceCellView> mExemptCellViewSet = mExemptSearcher.getAllExemptViews();
        if (mExemptCellViewSet == null) {
            completeAllTask(true, true);
            return;
        }

        for (InsuranceCellView cellView : mExemptCellViewSet) {
            createNewTask(applicant, insured, cellView);
        }
    }

    /**
     * 添加豁免险后调用
     *
     * @param applicant 投保人
     * @param insured   被保人
     */
    public void updateExemptViewAfterAddExempt(Customer applicant, Customer insured) {
        if (mExemptSearcher.checkContainerNull()) {
            completeAllTask(true, true);
            return;
        }
        // 获取最后一个ChildView，即刚刚添加的豁免险View
        InsuranceCellView cellView = mExemptSearcher.getLastCellView();
//        updateExemptionView(cellView, applicant, insured);
        createNewTask(applicant, insured, cellView);
    }

    /**
     * 生成一个隐式产品计算器Url
     *
     * @param mArg
     * @return
     */
    private String createWebUrl(ArgProductOption mArg) {
        if (mArg == null) {
            return Constant.PROPOSAL_CALCULATOR_WEB_URL;
        }
        try {
            return Constant.PROPOSAL_CALCULATOR_WEB_URL
                    + "proId=" + DataUtils.encodeParamValue(mArg.productId + "") + "&"
                    + "age=" + DataUtils.encodeParamValue(mArg.age) + "&"
                    + "sex=" + DataUtils.encodeParamValue(mArg.sex) + "&"
                    + "profession=" + DataUtils.encodeParamValue(mArg.profession) + "&"
                    + "birthday=" + DataUtils.encodeParamValue(mArg.birthday) + "&"
                    + "isExempt=true" + "&"
                    + "options=" + DataUtils.encodeParamValue(mArg.createOptionsJson());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return Constant.PROPOSAL_CALCULATOR_WEB_URL;
    }

    /**
     * 生成一个计算器编辑参数
     *
     * @param product
     * @return
     */
    private ArgProductOption createProductOptionArg(InsuranceEntity product, Customer customer) {
        if (product == null) {
            return null;
        }
        ArgProductOption arg = new ArgProductOption();
        arg.productId = product.productId + "";
        arg.productName = product.productName;

        arg.age = customer == null ? "30" : customer.getAge() + "";
        arg.sex = customer == null ? "1" : customer.getSex() + "";
        arg.profession = customer == null ? "1" : customer.getCareerCategory() + "";
        arg.birthday = customer == null ? "" : DateUtils.formatDate(customer.getBirthday());

        arg.coverage = product == null ? null : product.coverage;
        arg.premium = product == null ? null : product.premium;
        arg.coveragePeriod = product == null ? null : product.coveragePeriod;
        arg.paymentPeriod = product == null ? null : product.paymentPeriod;

        arg.extraOptions = product == null ? null : product.extraData;
        return arg;
    }

    /**
     * 解析计算器返回的保险选项
     *
     * @param json
     * @return
     */
    private InsuranceCalculator parseCalculator(String json) {
        if (TextUtils.isEmpty(json)) {
            return null;
        }
        InsuranceCalculator calculator = new InsuranceCalculator();
        try {
            JSONObject jsonObject = new JSONObject(json);
            JSONArray optionArr = jsonObject.getJSONArray("options");
            if (optionArr == null || optionArr.length() == 0) {
                return null;
            }
            for (int i = 0; i < optionArr.length(); i++) {
                JSONObject option = optionArr.getJSONObject(i);
                if (option != null) {
                    calculator.init(option.getString("fieldName"), option.getString("displayName"), option.getString("value"));
                }
            }
            return calculator;
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取指定豁免险的保额： 豁免所有保险保额求和
     *
     * @param data 指定豁免险
     * @return
     */
    private double getExemptCoverage(InsuranceEntity data) {
        if (data == null || data.exemptProduct == null || data.exemptProduct.size() == 0) {
            return 0;
        }
        List<InsuranceEntity> mAllProductsData = mExemptSearcher.getAllProductsData();
        int count = mAllProductsData == null ? 0 : mAllProductsData.size();
        if (count == 0) {
            return 0;
        }
        double mTotalCoverage = 0;
        for (int i = 0; i < count; i++) {
            InsuranceEntity productData = mAllProductsData.get(i);
            if (productData != null) {
//                if (productData.isMain == 1) {
//                    productData.planCode = "*";
//                }
                if (data.exemptProduct.contains("*") && productData.isMain == 1) {
                    // 豁免主险，则加入主险
                    mTotalCoverage += Double.valueOf(productData.premium.value);
                }
                if (data.exemptProduct.contains(productData.planCode)) {
                    try {
                        mTotalCoverage += Double.valueOf(productData.premium.value);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return mTotalCoverage;
    }

    /**
     * 更新指定豁免险的保额与保费
     *
     * @param view      豁免险的View
     * @param applicant 投保人
     * @param insured   被保人
     */
    public void updateExemptionView(InsuranceCellView view, Customer applicant, Customer insured) {
        if (view == null) {
            recycleTask();
            return;
        }
        InsuranceEntity exemptData = view.getData();
        if (exemptData == null) {
            recycleTask();
            return;
        }
        // 求保额
        double totalCoverage = getExemptCoverage(exemptData);
        /**
         * 整型去.策略
         * 1） 整型带. -> 整型，如20.00 -> 20
         * 2) 浮点型保持
         */
        String converageIntValue = DataUtils.getIntValue(totalCoverage);
        exemptData.coverage.value = converageIntValue;
        exemptData.coverage.displayName = converageIntValue;

        // 求保费
        ArgProductOption options = null;
        if (exemptData.getExemptionType() == 1) { // 豁免： 投保人
            options = createProductOptionArg(exemptData, applicant);
        } else if (exemptData.getExemptionType() == 2) { // 豁免： 被保人
            options = createProductOptionArg(exemptData, insured);
        }

        String calculatorUrl = createWebUrl(options);
        WebViewStack.WebViewObject webViewObject = createWebViewObject(calculatorUrl);
        if (webViewObject == null) {
            recycleTask();
            return;
        }
        Logger.i("Url [" + webViewObject.id + "] = " + calculatorUrl);
        view.setTag(webViewObject.id);
        mViewStack.put(webViewObject.id, view, exemptData); // 调用Js的线程在JsBridge线程，会导致View更新混乱；此处id绑定View,来对应正确的View

        mMoveDataHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg != null && msg.what == 1) {
                    WebViewCallback callback = (WebViewCallback) msg.obj;
                    calculatePremiumByJs(callback);
                } else if (msg != null && msg.what == -1) {
                    /*页面加载失败*/
                    view.setData(exemptData);
                    recycleTask();
                }
            }
        };
    }

    /**
     * 生成一个WebViewObject对象
     *
     * @param url
     * @return
     */
    private WebViewStack.WebViewObject createWebViewObject(String url) {
        WebView webview = new WebView(mContext);
        webview.getSettings().setJavaScriptEnabled(true);
        webview.setWebViewClient(new WebViewClient() {
            @Override
            public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
                super.onReceivedError(view, request, error);
                if (mMoveDataHandler != null) {
                    mMoveDataHandler.sendEmptyMessage(-1);
                }
            }
        });

        ProposalNativeAPI nativeAPI = new ProposalNativeAPI(mContext, this);
        WebViewCallback callback = new WebViewCallback()
                .with(webview)
                .addNativeInterface(nativeAPI, Constant.JSCallInstance);

        webview.loadUrl(url);

        WebViewStack.WebViewObject object = mWebViewStack.put(url, webview, callback);
        if (object != null && object.callback != null) {
            nativeAPI.setTag(object.callback.getId());
            nativeAPI.setUrl(object.callback.getTag());
        }

        return object;
    }

    /**
     * 解析Js结果
     *
     * @param id
     * @param calculator
     */
    private void parseJsResult(int id, InsuranceCalculator calculator) {
        ViewStack.ViewObject viewObject = mViewStack.getViewObject(id);
        if (viewObject == null || viewObject.isNull()) {
            return;
        }
        InsuranceEntity data = viewObject.data;
        if (calculator != null) {
            /* 将计算器返回的基础选项添加到data*/
            data.coverage = calculator.optCoverage;
            data.premium = calculator.optPremium;
            data.coveragePeriod = calculator.optCoveragePeriod;
            data.paymentPeriod = calculator.optPaymentPeriod;
            /* 将计算器返回的其余选项添加到data*/
            data.addExtraData(calculator.mOptionList);
        }
        InsuranceCellView cellView = viewObject.view;
        if (cellView == null) {
            return;
        }
        cellView.setData(data);
        mViewStack.remove(id);
        EventBus.getDefault().post(new ExemptResetEvent());
    }

    /**
     * 通过轮询方式调用Js计算保费
     */
    private void calculatePremiumByJs(WebViewCallback callback) {
        if (callback == null) {
            recycleTask();
            return;
        }
        callback.addJsInterface(EBTBottomWebDialog.JSGetProductOptions, response -> {
            Logger.i("++++Js-return： " + response);
            if (response == null || "".equals(response) || "null".equals(response)) {
                mWebViewStack.remove(callback.getId(), callback.getTag());
                recycleTask();
                return;
            }
            InsuranceCalculator calculator = parseCalculator(response);
            parseJsResult(callback.getId(), calculator);
            mWebViewStack.remove(callback.getId(), callback.getTag());
            recycleTask();
        });
    }

    /**
     * 销毁
     */
    public void destroyView() {
        mWebViewStack.clearAll();
        if (mViewStack != null) {
            mViewStack.clearAll();
        }
        clearTasks();
    }

    @Override
    public void onJsLoadSuccess(int id, String url) {
        WebViewStack.WebViewObject currentWebViewObject = mWebViewStack.get(id, url);
        if (currentWebViewObject != null) {
            Message msg = new Message();
            msg.what = 1;
            msg.obj = currentWebViewObject.callback;
            mMoveDataHandler.sendMessage(msg);
        } else {
            recycleTask();
        }
    }

    @Override
    public void start(ExemptTask task) {
        if (task != null) {
            showProgress();
            updateExemptionView(task.cellView, task.applicant, task.insured);
        } else {
            completeAllTask(true, true);
        }
    }
}
